<?php
// 应用公共文件
use app\common\service\admin\AuthService;
use think\facade\Db;
use think\facade\Route;
use think\facade\Request;
use think\facade\Config;

if ( ! function_exists('__')) {
    /**
     * 获取语言变量值，同TP lang()方法一致
     *
     * @param string $name
     * @param array  $vars
     * @param string $lang
     *
     * @return mixed
     */
    function __(string $name, array $vars = [], string $lang = '')
    {
        return lang($name, $vars, $lang);
    }
}
if ( ! function_exists('isUserLoggedIn')) {
    /**
     * 检查后台用户是否登录
     *
     * @param $userId
     *
     * @return bool
     * @throws Exception
     */
    function isUserLoggedIn($userId)
    {
        $adminUsers = session('admin_users') ?: [];

        return isset($adminUsers[$userId]);
    }
}

if ( ! function_exists('getCurrentUserInfo')) {
    /**
     * 获取后台的当前用户信息
     *
     * @param $userId
     *
     * @return mixed|null
     * @throws Exception
     */
    function getCurrentUserInfo($userId)
    {
        $adminUsers = session('admin_users') ?: [];

        return isset($adminUsers[$userId]) ? $adminUsers[$userId] : null;
    }
}

if ( ! function_exists('cmf_get_admin_id')) {
    /**
     * 获取后台已登录的管理员id
     * @return mixed|string|unknown|null
     */
    function cmf_get_admin_id()
    {
        // 获取当前用户ID，支持多用户登录
        $adminUsers = session('admin_users') ?: [];
        // 假设我们通过某种方式确定当前用户（比如通过请求参数或其他标识）
        // 这里需要根据实际业务逻辑来确定如何获取当前用户
        $currentUserId = session('current_admin_id');

        if ($currentUserId && isset($adminUsers[$currentUserId])) {
            return $currentUserId;
        }

        return null;
    }
}

if ( ! function_exists('cmf_get_admin_username')) {
    /**
     * 获取后台已登录的管理员用户名
     * @return string
     */
    function cmf_get_admin_username()
    {
        // 获取当前用户名，支持多用户登录
        $adminUsers    = session('admin_users') ?: [];
        $currentUserId = session('current_admin_id');

        if ($currentUserId && isset($adminUsers[$currentUserId])) {
            return $adminUsers[$currentUserId]['username'] ?? '';
        }

        return '';
    }
}

if ( ! function_exists('cmf_set_current_admin')) {
    /**
     * 设置当前管理员会话
     *
     * @param int   $userId   用户ID
     * @param array $userInfo 用户信息
     *
     * @return void
     */
    function cmf_set_current_admin($userId, $userInfo)
    {
        // 存储所有管理员信息
        $adminUsers          = session('admin_users') ?: [];
        $adminUsers[$userId] = $userInfo;
        session('admin_users', $adminUsers);

        // 设置当前管理员ID
        session('current_admin_id', $userId);
    }
}

if ( ! function_exists('cmf_get_current_admin_info')) {
    /**
     * 获取当前管理员完整信息
     * @return array|null
     */
    function cmf_get_current_admin_info()
    {
        $adminUsers    = session('admin_users') ?: [];
        $currentUserId = session('current_admin_id');

        if ($currentUserId && isset($adminUsers[$currentUserId])) {
            return $adminUsers[$currentUserId];
        }

        return null;
    }
}

if ( ! function_exists('cmf_admin_logout')) {
    /**
     * 管理员退出登录
     *
     * @param int|null $userId 指定用户ID，null表示当前用户
     *
     * @return void
     */
    function cmf_admin_logout($userId = null)
    {
        $adminUsers = session('admin_users') ?: [];

        if ($userId === null) {
            $userId = session('current_admin_id');
        }

        if ($userId && isset($adminUsers[$userId])) {
            unset($adminUsers[$userId]);
            session('admin_users', $adminUsers);
        }

        // 如果是当前用户退出，则清除当前用户标识
        if ($userId == session('current_admin_id')) {
            session('current_admin_id', null);
        }

        // 如果没有管理员在线了，清除整个会话键
        if (empty($adminUsers)) {
            session('admin_users', null);
        }
    }
}

if ( ! function_exists('cmf_get_admin_role_id')) {
    /**
     * 获取当前登录的管理员角色id
     * @return int
     */
    function cmf_get_admin_role_id($withself = true)
    {
        $libAuth = new AuthService();
        $roleId  = $libAuth->getChildrenGroupIds($withself);

        return $roleId;
    }
}

if ( ! function_exists('cmf_get_user_id')) {
    /**
     * 根据手机号获取前台会员id
     */
    function cmf_get_user_id($mobile)
    {
        $userModel = new app\common\model\User();
        $user      = $userModel->where(array('mobile' => $mobile))->find();
        if ($user) {
            return $user->id;
        } else {
            return false;
        }
    }
}
if ( ! function_exists('cmf_get_admin_ids')) {
    /**
     * 取出当前管理员所拥有权限的管理员
     *
     * @param $withself
     *
     * @return array
     */
    function cmf_get_admin_ids($withself = true): array
    {
        $libAuth  = new AuthService();
        $adminIds = $libAuth->getChildrenAdminIds($withself);

        return $adminIds;
    }
}

if ( ! function_exists('cmf_get_image_url')) {
    /**
     * 转化数据库保存图片的文件路径，为可以访问的url
     *
     * @param string $file  文件路径，数据存储的文件相对路径
     * @param string $style 图片样式
     *
     * @return string 图片链接
     */
    function cmf_get_image_url($file, $style = '')
    {
        if (empty($file)) {
            return '';
        }

        if (strpos($file, "http") === 0) {
            return $file;
        } else {
            if (strpos($file, "/") === 0) {
                return cmf_get_domain().$file;
            }
        }
    }
}

if ( ! function_exists('check_auth')) {
    /**
     * 按钮权限验证，可判断当前是否有权限操作
     *
     * @param string|array $rule_name 需要验证的规则列表,支持逗号分隔的权限规则或索引数组
     * @param int          $admin_id  可以选择用户id,默认为空：当前已登录用户
     */
    function check_auth($rule_name = '', $admin_id = '')
    {
        $Auth = AuthService::instance();

        if (empty($admin_id)) {
            $admin_id = cmf_get_admin_id();
        }

        return $Auth->check($rule_name, $admin_id);
    }
}

if ( ! function_exists('cmf_get_domain')) {
    /**
     * 返回带协议的域名
     */
    function cmf_get_domain()
    {
        return request()->domain();
    }
}

if ( ! function_exists('passwordHash')) {
    /**
     * 密码哈希
     *
     * @param        $password
     * @param string $algo
     *
     * @return false|string|null
     */
    function passwordHash($password, $algo = PASSWORD_DEFAULT)
    {
        // 确保 $algo 是字符串类型
        if ( ! is_string($algo)) {
            $algo = (string)$algo;
        }

        return password_hash($password, $algo);
    }
}

if ( ! function_exists('passwordVerify')) {
    /**
     * 验证密码哈希
     *
     * @param $password
     * @param $hash
     *
     * @return bool
     */
    function passwordVerify(string $password, string $hash): bool
    {
        return password_verify($password, $hash);
    }
}

if ( ! function_exists('write_error_log')) {
    /**
     * 记录日志
     *
     * @param mixed  $errArr         日志信息（字符串或数组）
     * @param string $path           日志路径（相对于日志根目录）
     * @param string $fileFix        日志文件前缀
     * @param int    $backtraceLevel 回溯层级（用于记录调用位置）
     *
     * @return bool 是否写入成功
     */
    function write_error_log($errArr, string $path = '', string $fileFix = 'log_', int $backtraceLevel = 0): bool
    {
        try {
            // 格式化日志内容
            $message = format_log_message($errArr);

            // 获取当前时间
            $dateTime = date('Y-m-d H:i:s');

            // 构建日志文本
            $logMessage = build_log_content($message, $dateTime, $backtraceLevel);

            // 确保日志目录存在
            $logDir = get_log_directory($path);
            if ( ! ensure_directory_exists($logDir)) {
                return false;
            }

            // 生成日志文件名
            $fileName = $fileFix.date('Ymd').'.txt';
            $filePath = $logDir.DIRECTORY_SEPARATOR.$fileName;

            // 写入日志文件
            return error_log($logMessage, 3, $filePath);

        } catch (Exception $e) {
            // 避免在日志函数中再次抛出异常
            return false;
        }
    }

    /**
     * 格式化日志消息
     *
     * @param mixed $errArr
     *
     * @return string
     */
    function format_log_message($errArr): string
    {
        if (is_array($errArr)) {
            return json_encode($errArr, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
        }

        if (is_string($errArr)) {
            return $errArr;
        }

        if (is_object($errArr) && method_exists($errArr, '__toString')) {
            return (string)$errArr;
        }

        // 对于其他类型，使用 var_export 格式化
        return var_export($errArr, true);
    }

    /**
     * 构建日志内容
     *
     * @param string $message
     * @param string $dateTime
     * @param int    $backtraceLevel
     *
     * @return string
     */
    function build_log_content(string $message, string $dateTime, int $backtraceLevel = 0): string
    {
        $logContent = '';
        $logContent .= "【{$dateTime}】".PHP_EOL;

        // 添加调用位置信息（如果需要）
        if ($backtraceLevel > 0) {
            $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, $backtraceLevel + 1);
            if (isset($backtrace[$backtraceLevel])) {
                $trace      = $backtrace[$backtraceLevel];
                $file       = $trace['file'] ?? 'unknown';
                $line       = $trace['line'] ?? 'unknown';
                $function   = isset($trace['class']) ? ($trace['class'].$trace['type'].$trace['function']) : ($trace['function'] ?? 'unknown');
                $logContent .= "[位置: {$file}:{$line} in {$function}]".PHP_EOL;
            }
        }

        $logContent .= $message.PHP_EOL;
        $logContent .= str_repeat('=', 50).PHP_EOL.PHP_EOL;

        return $logContent;
    }

    /**
     * 获取日志目录路径
     *
     * @param string $path
     *
     * @return string
     */
    function get_log_directory(string $path): string
    {
        $rootPath = root_path(); // TP6获取根目录

        return $rootPath."public".DIRECTORY_SEPARATOR."log".DIRECTORY_SEPARATOR.$path;
    }

    /**
     * 确保目录存在
     *
     * @param string $directory
     *
     * @return bool
     */
    function ensure_directory_exists(string $directory): bool
    {
        if (is_dir($directory)) {
            return true;
        }

        return mkdir($directory, 0755, true);
    }
}

if ( ! function_exists('get_client_ip')) {
    /**
     * 获取客户端IP地址
     *
     * @param integer $type 返回类型 0 返回IP地址 1 返回IPV4地址数字
     * @param boolean $adv  是否进行高级模式获取（有可能被伪装）
     *
     * @return string
     */
    function get_client_ip($type = 0, $adv = true)
    {
        return request()->ip($type, $adv);
    }
}

if ( ! function_exists('get_config')) {
    /**
     * 获取系统配置信息(config表)
     *
     * @param $key 键值，可为空，为空获取整个数组
     *
     * @return array|string
     */
    function get_config($key = '')
    {
        $cacheData = cache('cacheSystemConfig');
        if ( ! empty($cacheData)) {
            $data = $cacheData;
        } else {
            $data = Db::name('config')->where('status', 1)->select()->toArray();
            cache('cacheSystemConfig', $data);
        }
        $configs = array();
        foreach ($data as $val) {
            $configs[$val['name']] = $val['value'];
        }
        if ( ! $key) {
            return $configs;
        } else {
            return array_key_exists($key, $configs) ? $configs[$key] : '';
        }
    }
}

if ( ! function_exists('xdebug')) {
    /**
     * debug调试
     * 该调试是打印到指定文件夹 public/xdebug/20230225.txt(文件命名取当前年月日)
     *
     * @param string|array $data   打印信息
     * @param string       $type   类型
     * @param string       $suffix 文件后缀名
     * @param bool         $force
     * @param null         $file
     */
    function xdebug($data, $type = 'xdebug', $suffix = null, $force = false, $file = null)
    {
        ! is_dir(public_path().'xdebug/') && mkdir(public_path().'xdebug/');
        if (is_null($file)) {
            $file = is_null($suffix) ? public_path().'xdebug/'.date('Ymd').'.txt' : public_path().'xdebug/'.date('Ymd')."_{$suffix}".'.txt';
        }
        file_put_contents($file,
            "[".date('Y-m-d H:i:s')."] "."========================= {$type} ===========================".PHP_EOL,
            FILE_APPEND);
        $str = (is_string($data) ? $data : (is_array($data) || is_object($data) ? print_r($data,
                true) : var_export($data, true))).PHP_EOL;

        $force ? file_put_contents($file, $str) : file_put_contents($file, $str, FILE_APPEND);
    }
}

/**
 * curl -get请求
 *
 * @param string $url URL to fetch
 */
if ( ! function_exists('curl_get')) {
    function curl_get($url)
    {
        $ch       = curl_init();
        $header[] = "";
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_REFERER, $url);
        curl_setopt($ch, CURLOPT_USERAGENT,
            "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36");
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        $content = curl_exec($ch);
        curl_close($ch);

        return $content;
    }
}

/**
 * curl post 请求
 *
 * @param $post_url  请求地址
 * @param $post_data 请求数据
 *
 * @return bool|mixed|string
 */
if ( ! function_exists('curl_post')) {
    function curl_post($post_url, $post_data, $header = [])
    {
        if (is_array($post_data)) {
            $post_data = http_build_query($post_data);
        }
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
        curl_setopt($ch, CURLOPT_URL, $post_url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
        curl_setopt($ch, CURLOPT_USERAGENT, '');
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        $output = curl_exec($ch);
        curl_close($ch);

        return $output;
    }
}

if ( ! function_exists('is_file')) {
    /**
     * 判断内容是否为文件
     *
     * @param $file
     *
     * @return bool
     */
    function is_file($file)
    {
        if (is_file($file) !== false) {
            return true;
        } else {
            return false;
        }
    }

}

if ( ! function_exists('array_format_key')) {
    /**
     * 二位数组重新组合数据
     *
     * @param $array
     * @param $key
     *
     * @return array
     */
    function array_format_key($array, $key)
    {
        $newArray = [];
        foreach ($array as $vo) {
            $newArray[$vo[$key]] = $vo;
        }

        return $newArray;
    }

}

if ( ! function_exists('get_dir')) {
    /**
     * 获取文件目录列表,该方法返回数组
     */
    function get_dir($dir)
    {
        $dirArray[] = null;
        if (false != ($handle = opendir($dir))) {
            $i = 0;
            while (false !== ($file = readdir($handle))) {
                //去掉"“.”、“..”以及带“.xxx”后缀的文件
                if ($file != "." && $file != ".." && ! strpos($file, ".")) {
                    $dirArray[$i] = $file;
                    $i++;
                }
            }
            //关闭句柄
            closedir($handle);
        }

        return $dirArray;
    }
}

if ( ! function_exists('dir_path')) {
    /**
     * 列出目录下所有文件
     *
     * @param string $path 路径
     * @param string $exts 扩展名
     * @param array  $list 增加的文件列表
     *
     * @return  array  所有满足条件的文件
     */
    function dir_path($path)
    {
        $path = str_replace('\\', '/', $path);
        if (substr($path, -1) != '/') {
            $path = $path.'/';
        }

        return $path;
    }
}

if ( ! function_exists('dir_delete')) {
    /**
     * 删除目录及目录下面的所有文件
     *
     * @param string $dir 路径
     *
     * @return  bool   如果成功则返回 TRUE，失败则返回 FALSE
     */
    function dir_delete($dir)
    {
        $dir = dir_path($dir);
        if ( ! is_dir($dir)) {
            return false;
        }
        $list = glob($dir.'*');
        foreach ($list as $v) {
            is_dir($v) ? dir_delete($v) : @unlink($v);
        }

        return @rmdir($dir);
    }
}

if ( ! function_exists('sizecount')) {
    /**
     * 转换字节数为其他单位
     *
     * @param string $filesize 字节大小
     *
     * @return    string    返回大小
     */
    function sizecount($filesize)
    {
        if ($filesize >= 1073741824) {
            $filesize = round($filesize / 1073741824 * 100) / 100 .' GB';
        } elseif ($filesize >= 1048576) {
            $filesize = round($filesize / 1048576 * 100) / 100 .' MB';
        } elseif ($filesize >= 1024) {
            $filesize = round($filesize / 1024 * 100) / 100 .' KB';
        } else {
            $filesize = $filesize.' Bytes';
        }

        return $filesize;
    }
}

if ( ! function_exists('convert_size_to_kb')) {
    /**
     * 将带有单位的文件大小字符串转换为 KB
     *
     * @param string $sizeStr 带有单位的文件大小字符串，如 "2M", "1024K"
     *
     * @return int 文件大小（KB）
     */
    function convert_size_to_kb($sizeStr)
    {
        $unit = strtoupper(substr($sizeStr, -1));
        $size = (int)$sizeStr;

        switch ($unit) {
            case 'G':
                $size *= 1024 * 1024;
                break;
            case 'M':
                $size *= 1024;
                break;
            case 'K':
                // 已经是 KB，无需转换
                break;
            default:
                $size /= 1024;
                break;
        }

        return $size;
    }
}

if ( ! function_exists('camelize')) {
    /**
     * 下划线转驼峰
     * 思路:
     * step1.原字符串转小写,原字符串中的分隔符用空格替换,在字符串开头加上分隔符
     * step2.将字符串中每个单词的首字母转换为大写,再去空格,去字符串首部附加的分隔符.
     */
    function camelize($uncamelized_words, $separator = '_')
    {
        $uncamelized_words = $separator.str_replace($separator, " ", strtolower($uncamelized_words));

        return ltrim(str_replace(" ", "", ucwords($uncamelized_words)), $separator);
    }
}

if ( ! function_exists('uncamelize')) {
    /**
     * 　　* 驼峰命名转下划线命名
     * 　　* 思路:
     * 　　* 小写和大写紧挨一起的地方,加上分隔符,然后全部转小写
     * 　　*/
    function uncamelize($camelCaps, $separator = '_')
    {
        return strtolower(preg_replace('/([a-z])([A-Z])/', "$1".$separator."$2", $camelCaps));
    }
}

if ( ! function_exists('cmf_parse_name')) {
    /**
     * 字符串命名风格转换
     * type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格
     *
     * @param string  $name    字符串
     * @param integer $type    转换类型
     * @param bool    $ucfirst 首字母是否大写（驼峰规则）
     *
     * @return string
     */
    function cmf_parse_name($name, $type = 0, $ucfirst = true)
    {
        if ($type) {
            $name = preg_replace_callback('/_([a-zA-Z])/', function ($match) {
                return strtoupper($match[1]);
            }, $name);

            return $ucfirst ? ucfirst($name) : lcfirst($name);
        }

        return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_"));
    }
}

if ( ! function_exists('cmf_scan_dir')) {
    /**
     * 替代scan_dir的方法
     *
     * @param string $pattern 检索模式 搜索模式 *.txt,*.doc; (同glog方法)
     * @param int    $flags
     * @param        $pattern
     *
     * @return array
     */
    function cmf_scan_dir($pattern, $flags = null)
    {
        $files = glob($pattern, $flags);
        if (empty($files)) {
            $files = [];
        } else {
            $files = array_map('basename', $files);
        }

        return $files;
    }
}

if ( ! function_exists('file_down')) {
    /**
     * 文件下载
     *
     * @param $filepath 文件路径
     * @param $filename 文件名称
     */
    function file_down($filepath, $filename = '')
    {
        if ( ! $filename) {
            $filename = basename($filepath);
        }
        if (is_ie()) {
            $filename = rawurlencode($filename);
        }
        $filetype = file_ext($filename);
        $filesize = sprintf("%u", filesize($filepath));
        if (ob_get_length() !== false) {
            @ob_end_clean();
        }
        header('Pragma: public');
        header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
        header('Cache-Control: no-store, no-cache, must-revalidate');
        header('Cache-Control: pre-check=0, post-check=0, max-age=0');
        header('Content-Transfer-Encoding: binary');
        header('Content-Encoding: none');
        header('Content-type: '.$filetype);
        header('Content-Disposition: attachment; filename="'.$filename.'"');
        header('Content-length: '.$filesize);
        readfile($filepath);
        exit;
    }
}

if ( ! function_exists('is_ie')) {
    /**
     * IE浏览器判断
     */
    function is_ie()
    {
        $useragent = strtolower($_SERVER['HTTP_USER_AGENT']);
        if ((strpos($useragent, 'opera') !== false) || (strpos($useragent, 'konqueror') !== false)) {
            return false;
        }
        if (strpos($useragent, 'msie ') !== false) {
            return true;
        }

        return false;
    }
}

if ( ! function_exists('file_ext')) {
    /**
     * 取得文件扩展
     *
     * @param $filename 文件名
     *
     * @return 扩展名
     */
    function file_ext($filename)
    {
        return strtolower(trim(substr(strrchr($filename, '.'), 1, 10)));
    }
}

if ( ! function_exists('array2level')) {
    /**
     * 数组层级缩进转换
     *
     * @param array $array 源数组
     * @param int   $pid
     * @param int   $level
     *
     * @return array
     */
    function array2level($array, $pid = 0, $level = 1)
    {
        static $list = [];
        foreach ($array as $v) {
            if ($v['pid'] == $pid) {
                $v['level'] = $level;
                $list[]     = $v;
                array2level($array, $v['id'], $level + 1);
            }
        }

        return $list;
    }
}

if ( ! function_exists('str_cut')) {
    /**
     * 字符截取
     *
     * @param $string    要截取的字符串
     * @param $length    截取长度
     * @param $dot       截取之后用什么表示
     * @param $code      编码格式，支持UTF8/GBK
     */
    function str_cut($string, $length, $dot = '...', $code = 'utf-8')
    {
        $strlen = strlen($string);
        if ($strlen <= $length) {
            return $string;
        }
        $string = str_replace(array(
            ' ',
            '&nbsp;',
            '&amp;',
            '&quot;',
            '&#039;',
            '&ldquo;',
            '&rdquo;',
            '&mdash;',
            '&lt;',
            '&gt;',
            '&middot;',
            '&hellip;',
            '\r\n'
        ), array('∵', ' ', '&', '"', "'", '“', '”', '—', '<', '>', '·', '…'), $string);
        $strcut = '';
        if ($code == 'utf-8') {
            $length = intval($length - strlen($dot) - $length / 3);
            $n      = $tn = $noc = 0;
            while ($n < strlen($string)) {
                $t = ord($string[$n]);
                if ($t == 9 || $t == 10 || (32 <= $t && $t <= 126)) {
                    $tn = 1;
                    $n++;
                    $noc++;
                } elseif (194 <= $t && $t <= 223) {
                    $tn  = 2;
                    $n   += 2;
                    $noc += 2;
                } elseif (224 <= $t && $t <= 239) {
                    $tn  = 3;
                    $n   += 3;
                    $noc += 2;
                } elseif (240 <= $t && $t <= 247) {
                    $tn  = 4;
                    $n   += 4;
                    $noc += 2;
                } elseif (248 <= $t && $t <= 251) {
                    $tn  = 5;
                    $n   += 5;
                    $noc += 2;
                } elseif ($t == 252 || $t == 253) {
                    $tn  = 6;
                    $n   += 6;
                    $noc += 2;
                } else {
                    $n++;
                }
                if ($noc >= $length) {
                    break;
                }
            }
            if ($noc > $length) {
                $n -= $tn;
            }
            $strcut = substr($string, 0, $n);
            $strcut = str_replace(array('∵', '&', '"', "'", '“', '”', '—', '<', '>', '·', '…'), array(
                ' ',
                '&amp;',
                '&quot;',
                '&#039;',
                '&ldquo;',
                '&rdquo;',
                '&mdash;',
                '&lt;',
                '&gt;',
                '&middot;',
                '&hellip;'
            ), $strcut);
        } else {
            $dotlen      = strlen($dot);
            $maxi        = $length - $dotlen - 1;
            $current_str = '';
            $search_arr  = array('&', ' ', '"', "'", '“', '”', '—', '<', '>', '·', '…', '∵');
            $replace_arr = array(
                '&amp;',
                '&nbsp;',
                '&quot;',
                '&#039;',
                '&ldquo;',
                '&rdquo;',
                '&mdash;',
                '&lt;',
                '&gt;',
                '&middot;',
                '&hellip;',
                ' '
            );
            $search_flip = array_flip($search_arr);
            for ($i = 0; $i < $maxi; $i++) {
                $current_str = ord($string[$i]) > 127 ? $string[$i].$string[++$i] : $string[$i];
                if (in_array($current_str, $search_arr)) {
                    $key         = $search_flip[$current_str];
                    $current_str = str_replace($search_arr[$key], $replace_arr[$key], $current_str);
                }
                $strcut .= $current_str;
            }
        }

        return $strcut.$dot;
    }
}

/**
 * 获取客户端操作系统
 * php_uname()
 *
 * @param $agent //$_SERVER['HTTP_USER_AGENT']
 *
 * @return array[os]            操作系统名称
 * @return array[os_ver]        操作系统版本号
 * @return array[equipment]     终端设备类型
 */
function get_client_os($agent = '')
{
    $os        = '';
    $equipment = '';
    $os_ver    = php_uname();
    //window系统
    $agent = strtolower($agent);
    if (stripos($agent, 'window')) {
        $os        = 'Windows';
        $equipment = '电脑';
        if (preg_match('/nt 6.0/i', $agent)) {
            $os_ver = 'Vista';
        } elseif (preg_match('/nt 11.0/i', $agent)) {
            $os_ver = '11';
        } elseif (preg_match('/nt 10.0/i', $agent)) {
            $os_ver = '10';
        } elseif (preg_match('/nt 6.3/i', $agent)) {
            $os_ver = '8.1';
        } elseif (preg_match('/nt 6.2/i', $agent)) {
            $os_ver = '8.0';
        } elseif (preg_match('/nt 6.1/i', $agent)) {
            $os_ver = '7';
        } elseif (preg_match('/nt 5.1/i', $agent)) {
            $os_ver = 'XP';
        } elseif (preg_match('/nt 5/i', $agent)) {
            $os_ver = '2000';
        } elseif (preg_match('/nt 98/i', $agent)) {
            $os_ver = '98';
        } elseif (preg_match('/nt/i', $agent)) {
            $os_ver = 'nt';
        } else {
            $os_ver = '';
        }
        if (preg_match('/x64/i', $agent)) {
            $os .= '(x64)';
        } elseif (preg_match('/x32/i', $agent)) {
            $os .= '(x32)';
        }
    } elseif (stripos($agent, 'linux')) {
        if (stripos($agent, 'android')) {
            preg_match('/android\s([\d\.]+)/i', $agent, $match);
            $os        = 'Android';
            $equipment = 'Mobile phone';
            $os_ver    = $match[1];
        } else {
            $os = 'Linux';
        }
    } elseif (stripos($agent, 'unix')) {
        $os = 'Unix';
    } elseif (preg_match('/iPhone|iPad|iPod/i', $agent)) {
        preg_match('/OS\s([0-9_\.]+)/i', $agent, $match);
        $os     = 'IOS';
        $os_ver = str_replace('_', '.', $match[1]);
        if (preg_match('/iPhone/i', $agent)) {
            $equipment = 'iPhone';
        } elseif (preg_match('/iPad/i', $agent)) {
            $equipment = 'iPad';
        } elseif (preg_match('/iPod/i', $agent)) {
            $equipment = 'iPod';
        }
    } elseif (stripos($agent, 'mac os')) {
        preg_match('/Mac OS X\s([0-9_\.]+)/i', $agent, $match);
        $os        = 'Mac OS X';
        $equipment = '电脑';
        $os_ver    = str_replace('_', '.', $match[1]);
    } else {
        $os = 'Other';
    }

    return ['os' => $os, 'os_ver' => $os_ver, 'equipment' => $equipment];
}

if ( ! function_exists('get_client_browser')) {
    /**
     * 获取客户端浏览器以及版本号
     *
     * @param $agent //$_SERVER['HTTP_USER_AGENT']
     *
     * @return array[browser]       浏览器名称
     * @return array[browser_ver]   浏览器版本号
     */
    function get_client_browser($agent = '')
    {
        $browser     = '';
        $browser_ver = '';
        if (preg_match('/OmniWeb\/(v*)([^\s|;]+)/i', $agent, $regs)) {
            $browser     = 'OmniWeb';
            $browser_ver = $regs[2];
        }
        if (preg_match('/Netscape([\d]*)\/([^\s]+)/i', $agent, $regs)) {
            $browser     = 'Netscape';
            $browser_ver = $regs[2];
        }
        if (preg_match('/safari\/([^\s]+)/i', $agent, $regs)) {
            $browser     = 'Safari';
            $browser_ver = $regs[1];
        }
        if (preg_match('/MSIE\s([^\s|;]+)/i', $agent, $regs)) {
            $browser     = 'Internet Explorer';
            $browser_ver = $regs[1];
        }
        if (preg_match('/Opera[\s|\/]([^\s]+)/i', $agent, $regs)) {
            $browser     = 'Opera';
            $browser_ver = $regs[1];
        }
        if (preg_match('/NetCaptor\s([^\s|;]+)/i', $agent, $regs)) {
            $browser     = '(Internet Explorer '.$browser_ver.') NetCaptor';
            $browser_ver = $regs[1];
        }
        if (preg_match('/Maxthon/i', $agent, $regs)) {
            $browser     = '(Internet Explorer '.$browser_ver.') Maxthon';
            $browser_ver = '';
        }
        if (preg_match('/360SE/i', $agent, $regs)) {
            $browser     = '(Internet Explorer '.$browser_ver.') 360SE';
            $browser_ver = '';
        }
        if (preg_match('/SE 2.x/i', $agent, $regs)) {
            $browser     = '(Internet Explorer '.$browser_ver.') 搜狗';
            $browser_ver = '';
        }
        if (preg_match('/FireFox\/([^\s]+)/i', $agent, $regs)) {
            $browser     = 'FireFox';
            $browser_ver = $regs[1];
        }
        if (preg_match('/Lynx\/([^\s]+)/i', $agent, $regs)) {
            $browser     = 'Lynx';
            $browser_ver = $regs[1];
        }
        if (preg_match('/Chrome\/([^\s]+)/i', $agent, $regs)) {
            $browser     = 'Chrome';
            $browser_ver = $regs[1];
        }
        if (preg_match('/MicroMessenger\/([^\s]+)/i', $agent, $regs)) {
            $browser     = '微信浏览器';
            $browser_ver = $regs[1];
        }
        if ($browser != '') {
            return ['browser' => $browser, 'browser_ver' => $browser_ver];
        } else {
            return ['browser' => '未知', 'browser_ver' => ''];
        }
    }
}

if ( ! function_exists('get_ip_to_area')) {
    /**
     * 根据IP地址判断地区
     *
     * @param $clientIP
     *
     * @return string
     */
    function get_ip_to_area($clientIP)
    {
        $IpAddress = new IpAddress();
        if ($clientIP == '127.0.0.1') {
            $return = [
                'country'  => '',
                'province' => '',
                'city'     => '',
                'isp'      => '',
            ];

            return $return;
        }
        $address = $IpAddress->ipToAddress($clientIP);
        $return  = [
            'country'  => ! empty($address['country']) ? $address['country'] : '',
            'province' => ! empty($address['province']) ? $address['province'] : '',
            'city'     => ! empty($address['city']) ? $address['city'] : '',
            'isp'      => ! empty($address['isp']) ? $address['isp'] : '',
        ];

        return $return;
    }
}

if ( ! function_exists('list_sort_by')) {
    /**
     * 对查询结果集进行排序
     * @access public
     *
     * @param array  $list   查询结果
     * @param string $field  排序的字段名
     * @param array  $sortby 排序类型
     *                       asc正向排序 desc逆向排序 nat自然排序
     *
     * @return array
     * @author wapai 邮箱:wapai@foxmail.com
     */
    function list_sort_by($list, $field, $sortby = 'asc')
    {
        if (is_array($list)) {
            $refer = $resultSet = array();
            foreach ($list as $i => $data) {
                $refer[$i] = &$data[$field];
            }
            $refer = match ($sortby) {
                'asc' => asort($refer) ? $refer : $refer,
                'desc' => arsort($refer) ? $refer : $refer,
                'nat' => natcasesort($refer) ? $refer : $refer,
                default => $refer, // 默认情况，保持不变
            };
            foreach ($refer as $key => $val) {
                $resultSet[] = &$list[$key];
            }

            return $resultSet;
        }

        return false;
    }
}

if ( ! function_exists('new_addslashes')) {
    /**
     * 返回经addslashes处理过的字符串或数组
     *
     * @param $string 需要处理的字符串或数组
     *
     * @return mixed
     */
    function new_addslashes($string)
    {
        if ( ! is_array($string)) {
            return addslashes($string);
        }
        foreach ($string as $key => $val) {
            $string[$key] = new_addslashes($val);
        }

        return $string;
    }
}

if ( ! function_exists('arr_to_html')) {

    /**
     * 转换数据为HTML代码
     *
     * @param $data 数组
     *
     * @return bool|string
     */
    function arr_to_html($data)
    {
        if (is_array($data)) {
            $str = 'array(';
            foreach ($data as $key => $val) {
                if (is_array($val)) {
                    $str .= "'$key'=>".arr_to_html($val).",";
                } else {
                    //如果是变量的情况
                    if (strpos($val, '$') === 0) {
                        $str .= "'$key'=>$val,";
                    } else {
                        if (preg_match("/^([a-zA-Z_].*)\(/i", $val, $matches)) {
                            //判断是否使用函数
                            if (function_exists($matches[1])) {
                                $str .= "'$key'=>$val,";
                            } else {
                                $str .= "'$key'=>'".newAddslashes($val)."',";
                            }
                        } else {
                            $str .= "'$key'=>'".newAddslashes($val)."',";
                        }
                    }
                }
            }

            return $str.')';
        }

        return false;
    }
}

if ( ! function_exists('newAddslashes')) {
    /**
     * 返回经addslashes处理过的字符串或数组
     *
     * @param $string 需要处理的字符串或数组
     *
     * @return array|string
     */
    function newAddslashes($string)
    {
        if ( ! is_array($string)) {
            return addslashes($string);
        }
        foreach ($string as $key => $val) {
            $string[$key] = newAddslashes($val);
        }

        return $string;
    }
}

if ( ! function_exists('to_guid_string')) {
    /**
     * 根据PHP各种类型变量生成唯一标识号
     *
     * @param mixed $mix 变量
     *
     * @return string
     */
    function to_guid_string($mix)
    {
        if (is_object($mix)) {
            return spl_object_hash($mix);
        } elseif (is_resource($mix)) {
            $mix = get_resource_type($mix).strval($mix);
        } else {
            $mix = serialize($mix);
        }

        return md5($mix);
    }
}

if ( ! function_exists('cmf_array_column')) {
    /**
     * 兼容低版本的array_column
     *
     * @param  $array      多维数组
     * @param  $column_key 需要返回值的列
     * @param  $index_key  可选。作为返回数组的索引/键的列。
     *
     * @return array       返回一个数组，数组的值为输入数组中某个单一列的值。
     */
    function cmf_array_column($array, $column_key, $index_key = null)
    {
        if (function_exists('array_column')) {
            return array_column($array, $column_key, $index_key);
        }

        $result = array();
        foreach ($array as $key => $value) {
            if ( ! is_array($value)) {
                continue;
            }
            if ($column_key) {
                if ( ! isset($value[$column_key])) {
                    continue;
                }
                $tmp = $value[$column_key];
            } else {
                $tmp = $value;
            }
            if ($index_key) {
                $key = isset($value[$index_key]) ? $value[$index_key] : $key;
            }
            $result[$key] = $tmp;
        }

        return $result;
    }
}

if ( ! function_exists('hui_word_time')) {
    /**
     * 传入时间戳,计算距离现在的时间
     *
     * @param number $time 时间戳
     *
     * @return string     返回多少以前
     */
    function hui_word_time($time)
    {
        $time = (int)substr($time, 0, 10);
        $int  = time() - $time;
        $str  = '';
        if ($int <= 2) {
            $str = sprintf('刚刚', $int);
        } elseif ($int < 60) {
            $str = sprintf('%d秒前', $int);
        } elseif ($int < 3600) {
            $str = sprintf('%d分钟前', floor($int / 60));
        } elseif ($int < 86400) {
            $str = sprintf('%d小时前', floor($int / 3600));
        } elseif ($int < 1728000) {
            $str = sprintf('%d天前', floor($int / 86400));
        } else {
            $str = date('Y-m-d H:i:s', $time);
        }

        return $str;
    }
}

if ( ! function_exists('var_export_short')) {
    /**
     * var_export 格式化为5.4数组
     */
    function var_export_short($data, $return = true)
    {
        $dump = var_export($data, true);
        $dump = preg_replace('#(?:\A|\n)([ ]*)array \(#i', '[', $dump); // Starts
        $dump = preg_replace('#\n([ ]*)\),#', "\n$1],", $dump); // Ends
        $dump = preg_replace('#=> \[\n\s+\],\n#', "=> [],\n", $dump); // Empties
        if (gettype($data) == 'object') { // Deal with object states
            $dump = str_replace('__set_state(array(', '__set_state([', $dump);
            $dump = preg_replace('#\)\)$#', "])", $dump);
        } else {
            $dump = preg_replace('#\)$#', "]", $dump);
        }
        if ($return === true) {
            return $dump;
        } else {
            echo $dump;
        }
    }
}

if ( ! function_exists('build_suffix_image')) {
    /**
     * 生成文件后缀图片
     *
     * @param string $suffix 后缀
     * @param null   $background
     *
     * @return string
     */
    function build_suffix_image($suffix, $background = null, $w = '', $h = '')
    {
        $suffix = mb_substr(strtoupper($suffix), 0, 4);
        $total  = unpack('L', hash('adler32', $suffix, true))[1];
        $hue    = $total % 360;
        list($r, $g, $b) = hsv2rgb($hue / 360, 0.3, 0.9);

        $background = $background ? $background : "rgb({$r},{$g},{$b})";
        $w          = $w ? "width:".$w.'px;' : '';
        $h          = $h ? "height:".$h.'px;' : '';

        $icon = <<<EOT
        <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;{$w} {$h}" xml:space="preserve">
            <path style="fill:#E2E5E7;" d="M128,0c-17.6,0-32,14.4-32,32v448c0,17.6,14.4,32,32,32h320c17.6,0,32-14.4,32-32V128L352,0H128z"/>
            <path style="fill:#B0B7BD;" d="M384,128h96L352,0v96C352,113.6,366.4,128,384,128z"/>
            <polygon style="fill:#CAD1D8;" points="480,224 384,128 480,128 "/>
            <path style="fill:{$background};" d="M416,416c0,8.8-7.2,16-16,16H48c-8.8,0-16-7.2-16-16V256c0-8.8,7.2-16,16-16h352c8.8,0,16,7.2,16,16 V416z"/>
            <path style="fill:#CAD1D8;" d="M400,432H96v16h304c8.8,0,16-7.2,16-16v-16C416,424.8,408.8,432,400,432z"/>
            <g><text><tspan x="220" y="380" font-size="124" font-family="Verdana, Helvetica, Arial, sans-serif" fill="white" text-anchor="middle">{$suffix}</tspan></text></g>
        </svg>
EOT;

        return $icon;
    }
}

if ( ! function_exists('hsv2rgb')) {
    /*
    * 将HSV颜色转换为RGB
    */
    function hsv2rgb($h, $s, $v)
    {
        $r = $g = $b = 0;

        $i = floor($h * 6);
        $f = $h * 6 - $i;
        $p = $v * (1 - $s);
        $q = $v * (1 - $f * $s);
        $t = $v * (1 - (1 - $f) * $s);

        switch ($i % 6) {
            case 0:
                $r = $v;
                $g = $t;
                $b = $p;
                break;
            case 1:
                $r = $q;
                $g = $v;
                $b = $p;
                break;
            case 2:
                $r = $p;
                $g = $v;
                $b = $t;
                break;
            case 3:
                $r = $p;
                $g = $q;
                $b = $v;
                break;
            case 4:
                $r = $t;
                $g = $p;
                $b = $v;
                break;
            case 5:
                $r = $v;
                $g = $p;
                $b = $q;
                break;
        }

        return [
            floor($r * 255),
            floor($g * 255),
            floor($b * 255),
        ];
    }
}

if ( ! function_exists('get_templates')) {

    /**
     * 获取前台所有模板名（模板文件夹）
     * @return array
     */
    function get_templates()
    {
        $themePath  = public_path().'template'.DIRECTORY_SEPARATOR;
        $theme_list = get_dir($themePath);

        return $theme_list;
    }
}

if ( ! function_exists('get_template_path')) {

    /**
     * 获取前台模板主题根路径
     *
     * @param string $name 模块
     *
     * @return object|string
     */
    function get_template_path()
    {
        $indexTheme = ! empty(get_config('index_theme')) ? get_config('index_theme') : 'default';
        $themePath  = public_path().'template'.DIRECTORY_SEPARATOR.$indexTheme.DIRECTORY_SEPARATOR;

        return $themePath;
    }
}

if ( ! function_exists('get_tpl_name')) {
    /**
     * 获取对应模板文件
     *
     * @param type string 模板类型，如：list ， 列表模板
     *
     * @return array
     */
    function get_tpl_name()
    {
        $type = input('type', '');
        $path = get_template_path();
        $path = $path.$type.DIRECTORY_SEPARATOR;
        $list = str_replace($path, '', glob($path.'*.html'));

        $arr = [];
        foreach ($list as $key => $value) {
            if ( ! empty($searchValue) && $value != $searchValue) {
                continue;
            }
            $arr[]['name'] = $value;
        }

        return $arr;
    }
}

/**
 * 生成访问插件的url
 *
 * @param string $url    url格式：插件名://控制器名/方法
 * @param array  $vars   参数
 * @param bool   $domain 是否显示域名 或者直接传入域名
 *
 * @return string
 */
function cmf_plugin_url($url, $vars = [], $domain = false)
{
    /*global $CMF_GV_routes;

    if (empty($CMF_GV_routes)) {
        $routeModel    = new \app\common\model\RouteModel();
        $CMF_GV_routes = $routeModel->getRoutes();
    }*/

    $url              = parse_url($url);
    $case_insensitive = true;
    $plugin           = $case_insensitive ? cmf_parse_name($url['scheme']) : $url['scheme'];
    $controller       = $case_insensitive ? cmf_parse_name($url['host']) : $url['host'];
    $action           = trim($case_insensitive ? strtolower($url['path']) : $url['path'], '/');

    /* 解析URL带的参数 */
    if (isset($url['query'])) {
        parse_str($url['query'], $query);
        $vars = array_merge($query, $vars);
    }

    /* 基础参数 */
    $params = [
        '_plugin'     => $plugin,
        '_controller' => $controller,
        '_action'     => $action,
    ];

    $pluginUrl = '\\app\\index\\controller\\PluginController@index?'.http_build_query($params);

    if ( ! empty($vars) && ! empty($CMF_GV_routes[$pluginUrl])) {

        foreach ($CMF_GV_routes[$pluginUrl] as $actionRoute) {
            $sameVars = array_intersect_assoc($vars, $actionRoute['vars']);

            if (count($sameVars) == count($actionRoute['vars'])) {
                ksort($sameVars);
                $pluginUrl = $pluginUrl.'&'.http_build_query($sameVars);
                $vars      = array_diff_assoc($vars, $sameVars);
                break;
            }
        }
    }

    return url($pluginUrl, $vars, true, $domain);
}

/**
 * 添加钩子
 *
 * @param string $hook   钩子名称
 * @param mixed  $params 传入参数
 * @param bool   $once
 *
 * @return mixed
 */
/*function hook($hook, $params = null, $once = false)
{
    $hook = cmf_parse_name($hook, 1);

    return \think\facade\Event::trigger($hook, $params, $once);
}*/

/**
 * 添加钩子,只执行一个
 *
 * @param string $hook   钩子名称
 * @param mixed  $params 传入参数
 *
 * @return mixed
 */
/*function hook_one($hook, $params = null)
{
    $hook = cmf_parse_name($hook, 1);

    return \think\facade\Event::trigger($hook, $params, true);
}*/

/**
 * 获取插件类名
 *
 * @param string $name 插件名
 *
 * @return string
 *
 */
function cmf_get_plugin_class($name, $type = 'hook', $class = null)
{
    $name  = cmf_parse_name($name);
    $class = cmf_parse_name(is_null($class) ? $name : $class, 1);
    switch ($type) {
        case 'controller':
            $namespace = "\\addons\\".$name."\\controller\\".$class;
            break;
        default:
            $namespace = "\\addons\\".$name."\\Plugin";
    }

    return class_exists($namespace) ? $namespace : '';
}

/**
 * 获取插件配置
 *
 * @param string $name 插件名，大驼峰格式
 *
 * @return array
 */
function cmf_get_plugin_config($name)
{
    $class = cmf_get_plugin_class($name);
    if (class_exists($class)) {
        $plugin = new $class();

        return $plugin->getConfig();
    } else {
        return [];
    }
}

//数组排序
if ( ! function_exists('arrayOrder')) {
    function arrayOrder($array, $vkey)
    {
        $newArr = array();
        foreach ($array as $key => $v) {
            $newArr[$key][$vkey] = $v[$vkey];
        }
        array_multisort($newArr, SORT_DESC, $array);//SORT_DESC为降序，SORT_ASC为升序

        return $array;
    }
}

if ( ! function_exists('is_really_writable')) {
// 判断文件或目录是否有写的权限
    function is_really_writable($file)
    {
        if (DIRECTORY_SEPARATOR == '/' and @ ini_get("safe_mode") == false) {
            return is_writable($file);
        }
        if ( ! is_file($file) or ($fp = @fopen($file, "r+")) === false) {
            return false;
        }

        fclose($fp);

        return true;
    }
}

if ( ! function_exists('create_menu')) {
    /**
     * 创建菜单
     *
     * @param array  $menu 菜单数组
     * @param string $app  所属app(插件标识)
     *
     * @return bool
     */
    function create_menu(array $menu, string $app = '')
    {
        try {
            $bl = (new \app\common\model\AuthRule)->createMenu($menu, $app);
        } catch (\Exception $exception) {
            trace("创建菜单失败：".$exception->getMessage(), 'error');
            $bl = false;
        }
        app('cache')->tag('menu')->clear();

        return $bl;
    }
}

if ( ! function_exists('status_menu')) {
    /**
     * 更改状态
     *
     * @param integer $status 状态:normal-正常,hidden-禁用
     * @param string  $app
     */
    function status_menu($status = 1, string $app = '')
    {
        app('cache')->tag('menu')->clear();

        return \app\common\model\AuthRule::where(['app' => $app])->save(['is_menu' => $status]);
    }
}

if ( ! function_exists('del_menu')) {
    /**
     * 删除菜单
     *
     * @param string $app 插件标识
     *
     * @return bool
     */
    function del_menu(string $app)
    {
        app('cache')->tag('menu')->clear();
        $ids = \app\common\model\AuthRule::where(['app' => $app])->column('id');

        return \app\common\model\AuthRule::where(['app' => $app])->delete();
    }
}

if ( ! function_exists('check_cors_request')) {
    /**
     * 跨域检测
     */
    function check_cors_request()
    {
        //跨域访问的时候才会存在此字段
        if (isset($_SERVER['HTTP_ORIGIN']) && $_SERVER['HTTP_ORIGIN']) {
            $info        = parse_url($_SERVER['HTTP_ORIGIN']);
            $domainArr   = explode(',', Config::get('cms.cors_request_domain'));
            $domainArr[] = Request::host(true);
            if (in_array("*", $domainArr) || in_array($_SERVER['HTTP_ORIGIN'],
                    $domainArr) || (isset($info['host']) && in_array($info['host'], $domainArr))) {
                header("Access-Control-Allow-Origin: ".$_SERVER['HTTP_ORIGIN']);
            } else {
                header('HTTP/1.1 403 Forbidden');
                exit;
            }
            header('Access-Control-Allow-Credentials: true');
            header('Access-Control-Max-Age: 86400');
            if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
                if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD'])) {
                    header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
                }
                if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS'])) {
                    header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");
                }
                exit;
            }
        }
    }
}

if ( ! function_exists('isImageMagickAvailable')) {
    /**
     * 检查 ImageMagick库 是否可用
     * @return bool
     */
    function isImageMagickAvailable(): bool
    {
        // 首先检查是否启用了 imagick 扩展
        if (extension_loaded('imagick')) {
            return true;
        }

        // 检查是否可以通过 exec 执行 convert 命令
        if (function_exists('exec')) {
            try {
                // Windows 系统检查 magick 命令，其他系统检查 convert 命令
                $command = strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' ? 'magick --version' : 'convert --version';
                exec($command, $output, $returnCode);

                return $returnCode === 0;
            } catch (\Exception $e) {
                return false;
            }
        }

        return false;
    }
}
